//------------------------------------------------------------------------------
// <copyright file="RpcBinaryDataImpl.cpp" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

#include "stdafx.h"

#include "Encoding\Base64\Base64Encoder.h"

#include "RpcBinaryDataImpl.h"
#include <stdlib.h>
#include <memory>

using namespace Microsoft::Internal::GamesTest::Rpc::Server;

const wchar_t RpcBinaryDataImpl::TypeKey[] = L"__type";
const wchar_t RpcBinaryDataImpl::CompressionKey[] = L"compression";
const wchar_t RpcBinaryDataImpl::EncodingKey[] = L"encoding";
const wchar_t RpcBinaryDataImpl::DataKey[] = L"data";

RpcBinaryDataImpl::RpcBinaryDataImpl()
	: m_encoding(RpcBinaryToTextEncoding::Base64),
	m_compression(RpcCompressionScheme::NoCompression),
	m_data(nullptr),
	m_dataLength(0)
{
}

RpcBinaryDataImpl::RpcBinaryDataImpl(std::shared_ptr<unsigned __int8> data, unsigned int dataLength)
	: m_encoding(RpcBinaryToTextEncoding::Base64),
	m_compression(RpcCompressionScheme::NoCompression),
	m_data(data),
	m_dataLength(dataLength)
{
}
RpcBinaryDataImpl::RpcBinaryDataImpl(const RpcBinaryDataImpl& other)
	: m_encoding(other.m_encoding),
	m_compression(other.m_compression),
	m_data(nullptr),
	m_dataLength(other.m_dataLength)
{
	if( other.m_data != nullptr )
	{
		m_data.reset(new unsigned __int8[m_dataLength]);
		std::memcpy(m_data.get(), other.m_data.get(), m_dataLength);
	}
}

RpcBinaryDataImpl::RpcBinaryDataImpl(RpcBinaryDataImpl&& other)
	: m_encoding(other.m_encoding),
	m_compression(other.m_compression),
	m_data(std::move(other.m_data)),
	m_dataLength(other.m_dataLength)
{
}

RpcBinaryDataImpl::RpcBinaryDataImpl(_In_ const JsonNode& jsonObject):
	m_encoding(RpcBinaryToTextEncoding::Base64),
	m_compression(RpcCompressionScheme::NoCompression),
	m_data(nullptr),
	m_dataLength(0)
{
	if (jsonObject.Exists(EncodingKey))
	{
		m_encoding = (RpcBinaryToTextEncoding)jsonObject.GetIntegerValue(EncodingKey);
	}

	if (jsonObject.Exists(CompressionKey))
	{
		m_compression = (RpcCompressionScheme)jsonObject.GetIntegerValue(CompressionKey);
	}

	if (jsonObject.Exists(DataKey))
	{
		DecodeData(jsonObject.GetStringValue(DataKey));
	}
}

RpcBinaryDataImpl& RpcBinaryDataImpl::operator=(const RpcBinaryDataImpl& other)
{
	if (this == &other)
	{
		return *this;
	}

	m_encoding = other.m_encoding;
	m_compression = other.m_compression;
	m_dataLength = other.m_dataLength;
		
	if(other.m_data != nullptr)
	{
		m_data.reset(new unsigned __int8[m_dataLength]);
		std::memcpy(m_data.get(), other.m_data.get(), m_dataLength);
	}
	else
	{
		m_data = nullptr;
	}

	return *this;
}

RpcBinaryDataImpl& RpcBinaryDataImpl::operator=(RpcBinaryDataImpl&& other)
{
	if(this == &other)
	{
		return *this;
	}

	
	m_encoding = other.m_encoding;
	m_compression = other.m_compression;
	m_dataLength = other.m_dataLength;
	m_data = std::move(other.m_data);

	return *this;
}

RpcBinaryDataImpl::~RpcBinaryDataImpl()
{
	m_data = nullptr;
}

JsonNode RpcBinaryDataImpl::GetJson()
{
	JsonNode jsonObject;

	jsonObject.SetValue(TypeKey, L"RpcBinaryData:#Microsoft.Internal.GamesTest.Rpc.Client");
	jsonObject.SetValue(EncodingKey, (int)this->Encoding);
	jsonObject.SetValue(CompressionKey, (int)this->Compression);

	std::wstring data = EncodeData();
	jsonObject.SetValue(DataKey, JsonString(data.c_str(), (unsigned long)data.length()));

	return jsonObject;
}

std::wstring RpcBinaryDataImpl::EncodeData()
{
	if( m_data == nullptr )
	{
		return L"";
	}

	std::wstring output;

	switch( m_compression )
	{
	case RpcCompressionScheme::NoCompression:
	default:
		break;
	}

	switch( m_encoding )
	{
	case RpcBinaryToTextEncoding::Base64:
	default:
		output = Encoding::Base64::Base64Encoder::Encode(m_data.get(), m_dataLength);
		break;
	}
	
	return output;
}

void RpcBinaryDataImpl::DecodeData( const JsonString& encodedData)
{
	m_data = nullptr;

	if( encodedData.Empty() )
	{
		return;
	}

	switch( m_encoding )
	{
	case RpcBinaryToTextEncoding::Base64:
	default:		
		m_data = Encoding::Base64::Base64Encoder::Decode(encodedData, encodedData.GetLength(), m_dataLength);
		break;
	}	
	
	switch( m_compression )
	{
	case RpcCompressionScheme::NoCompression:
	default:
		break;
	}
}